/***************************************************************
*  Copyright (c) 2007 by GroupMe! Team (www.groupme.net)
*  All rights reserved.
*
*  This file is part of the GroupMe! Project. Source code of 
*  this project is closed and redistribution of this code is
*  prohibited. 
*  
*  Contact: http://www.groupme.net
*
*  This copyright notice MUST APPEAR in all copies of the file!
***************************************************************/
package net.groupme.search.strategy.folkrank;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.groupme.model.ObjectFactory;
import net.groupme.search.strategy.model.TAS;
import cern.colt.matrix.impl.SparseDoubleMatrix2D;

/**
 * created on 15 Jan 2008
 * 
 * This class extends the traditional FolkRank ranking strategy by using groups 
 * as artificial tags.
 * 
 * @author Fabian Abel, <a href="mailto:abel@l3s.de">abel@l3s.de</a>
 * @author last edited by: $Author: fabian $
 * 
 * @version $Revision: 1.3 $ $Date: 2010-02-03 10:55:39 $
 */
public class FolkRankWithGroupsAsArtificialTags extends NormalFolkRankRankingStrategy{

	//additional Mapping:
	protected Map<String, Integer> artificialTagIdColumMapping = null;
	
	/** artifcial group tags are constructed via the id of a group and this suffix */
	public static final String ARTIFICIAL_GROUP_TAG_SUFFIX = "g";
	
	/**
	 * Creates a new FolkRankWithGroupsAsArtificialTags instance. 
	 */
	public FolkRankWithGroupsAsArtificialTags() {
		super();
		artificialTagIdColumMapping = new HashMap<String, Integer>();
	}

	/* (non-Javadoc)
	 * @see net.groupme.search.strategy.folkrank.NormalFolkRankRankingStrategy#getName()
	 */
	@Override
	public String getName() {
		return "GFolkRankLight";
	}

	/* (non-Javadoc)
	 * @see net.groupme.search.strategy.folkrank.NormalFolkRankRankingStrategy#getDescription()
	 */
	@Override
	public String getDescription() {
		return "Groups are treated as artifical tags and assigned to contained resources, afterwards normal FolkRank";
	}
	
	/* (non-Javadoc)
	 * @see net.groupme.search.strategy.folkrank.NormalFolkRankRankingStrategy#constructAdjacencyMatrix()
	 */
	@Override
	protected void constructAdjacencyMatrix(){
		/* 1. Gather data: */
		Statement sqlStatement = null;
		ResultSet result = null;
		List<TAS> tagAssignments = null;
		
		try {
			sqlStatement = ObjectFactory.ds.getConnection().createStatement();
		
			tagAssignments = addNormalMappings(sqlStatement);
			//create artificial tags:
			result = sqlStatement.executeQuery("SELECT DISTINCT groupId FROM groupResource"); // where groupId in (Select distinct groupId from userTagGroupResource " + specificUserSql + ")");
			String artificialId = null;
			while(result.next()){
				artificialId = result.getInt(1) + ARTIFICIAL_GROUP_TAG_SUFFIX;
				artificialTagIdColumMapping.put(artificialId, position);
				position++;
			}
		
		
			/* 2. Compute the Matrix: */
			
			//construct Matrix
			int numberOfVertices = userIdColumMapping.size() + tagIdColumMapping.size() + resourceIdColumMapping.size() + artificialTagIdColumMapping.size();
			adjacencyMatrix = new SparseDoubleMatrix2D(numberOfVertices,numberOfVertices);
			
			//fill adjacency matrix
			fillMatrixWithNormalTagAssignments(tagAssignments);
			
			//row-wise 1-Norm:
			computeRowWiseThe1Norm();
		}catch (SQLException e) {
			e.printStackTrace();
		}
		
	}
	
	/* (non-Javadoc)
	 * @see net.groupme.search.strategy.folkrank.NormalFolkRankRankingStrategy#fillMatrixWithNormalTagAssignments(java.util.List)
	 */
	@Override
	protected void fillMatrixWithNormalTagAssignments(List<TAS> tagAssignments) {
		double userTagScore = 0.0;
		double tagResourceScore = 0.0;
		double userResourceScore = 0.0;
		int userPos = 0, tagPos = 0, resourcePos = 0, artificialPos = 0;
		try{
			for (TAS tas : tagAssignments) {
				userTagScore = FolkRank.computeUserTagWeight(tagAssignments, tas.getUserId(), tas.getTagId());
				tagResourceScore = FolkRank.computeTagResourceWeight(tagAssignments, tas.getTagId(), tas.getResourceId());
				userResourceScore = FolkRank.computeUserResourceWeight(tagAssignments, tas.getUserId(), tas.getResourceId());
				
				//get indices
				userPos = userIdColumMapping.get(tas.getUserId());
				tagPos = tagIdColumMapping.get(tas.getTagId());
				resourcePos = resourceIdColumMapping.get(tas.getResourceId());
				
				//set userTag-Score
				adjacencyMatrix.set(userPos, tagPos, userTagScore);
				adjacencyMatrix.set(tagPos,userPos, userTagScore);
				
				//set tagResource-Score:
				adjacencyMatrix.set(tagPos, resourcePos, tagResourceScore);
				adjacencyMatrix.set(resourcePos, tagPos, tagResourceScore);
				
				//set userResource-Score:
				adjacencyMatrix.set(userPos, resourcePos, userResourceScore);
				adjacencyMatrix.set(resourcePos, userPos, userResourceScore);
			}
		}catch (SQLException e) {
			e.printStackTrace();
		}
		
//		fill artificial tag stuff
		try {	
			ResultSet result = null;
			Statement sqlStatement = ObjectFactory.ds.getConnection().createStatement();
			//connection between resources and groups (= Artificial Tags):
			result = sqlStatement.executeQuery("SELECT resourceId, groupId FROM groupResource");// where resourceId in (Select distinct resourceId from userTagGroupResource " + specificUserSql + ") and groupId in (Select distinct groupId from groupResource where groupId in (Select distinct groupId from userTagGroupResource " + specificUserSql + "))");
			while(result.next()){
				//position within adjacency matrix:
				try{
				resourcePos = resourceIdColumMapping.get(result.getInt(1));
				artificialPos = artificialTagIdColumMapping.get(result.getInt(2) + ARTIFICIAL_GROUP_TAG_SUFFIX);
				
				//standard weight:
				adjacencyMatrix.set(resourcePos, artificialPos, FOLKRANK_SETTINGS.GROUP_WEIGHT);
				adjacencyMatrix.set(artificialPos, resourcePos, FOLKRANK_SETTINGS.GROUP_WEIGHT);
				} catch (Exception e) {
					System.out.println("Id: " + result.getString(2) + ARTIFICIAL_GROUP_TAG_SUFFIX + " - contained? " + artificialTagIdColumMapping.containsKey(result.getString(2) + ARTIFICIAL_GROUP_TAG_SUFFIX));
					e.printStackTrace();
				}
			}
			//connection between group-Resources and ArtificialGroupTags, and Group-Resource and User
			result = sqlStatement.executeQuery("SELECT DISTINCT a.groupId, b.userId FROM groupResource AS a join userGroup AS b ON a.groupId = b.groupId where b.role = 'owner'");
			while(result.next()){
				//get indices
				userPos = userIdColumMapping.get(result.getInt(2));
				resourcePos = resourceIdColumMapping.get(result.getInt(1));
				artificialPos = artificialTagIdColumMapping.get(result.getInt(1) + ARTIFICIAL_GROUP_TAG_SUFFIX);
				
				//set tagResource-Score:
				adjacencyMatrix.set(artificialPos, resourcePos, FOLKRANK_SETTINGS.GROUP_WEIGHT);
				adjacencyMatrix.set(resourcePos, artificialPos, FOLKRANK_SETTINGS.GROUP_WEIGHT);
				
				if(!FOLKRANK_SETTINGS.JUST_A_CONNECTION_BETWEEN_ARTIFICIAL_TAG_AND_GROUP){
					//set userTag-Score
					adjacencyMatrix.set(userPos, artificialPos, FOLKRANK_SETTINGS.GROUP_WEIGHT);
					adjacencyMatrix.set(artificialPos,userPos, FOLKRANK_SETTINGS.GROUP_WEIGHT);
					
					//set userResource-Score:
					adjacencyMatrix.set(userPos, resourcePos, FOLKRANK_SETTINGS.GROUP_WEIGHT);
					adjacencyMatrix.set(resourcePos, userPos, FOLKRANK_SETTINGS.GROUP_WEIGHT);
				}
			}
			ObjectFactory.ds.getConnection().close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

